/*
 * Copyright (c) 2008, Takashi Ito
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the authors nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "tansu_internal.h"
#include "tansu_nwif.h"
#include "tansu_upnp.h"
#include "light.h"

static const unsigned char *find_valid_mac(struct tansu_nwifs *nwifs)
{
    struct tansu_nwif *nwif;
    unsigned char zero[] = {0, 0, 0, 0, 0, 0};

    STAILQ_FOREACH(nwif, nwifs, entry) {
        if (memcmp(nwif->hwaddr, zero, sizeof(zero)))
            return nwif->hwaddr;
    }

    return NULL;
}

static struct tdom_doc *load_doc(const char *filename)
{
    int fd;
    char buff[32];
    int len;
    struct tdom_parser *parser;
    struct tdom_doc *doc;

    if ((parser = tdom_parser_new()) == NULL)
        return NULL;

    if ((fd = open(filename, O_RDONLY, 0)) == -1)
        goto out;

    for (;;) {
        len = read(fd, buff, sizeof(buff));
        if (len <= 0)
            goto out;

        len = tdom_parser_parse(parser, buff, len);
        if (len == 1)
            break;
        else if (len < 0)
            goto out;
    }

    doc = tdom_parser_get_doc(parser);
    tdom_parser_delete(parser);

    return doc;

out:
    if (fd != -1)
        tansu_socket_close(fd);

    tdom_parser_delete(parser);
    return NULL;
}

struct binary_light *create_binary_light(struct event_base *evbase,
                                         const char *dd,
                                         const char *switch_scpd,
                                         void (*cb)(struct evhttp_request *,
                                                    struct tansu_device *,
                                                    struct tansu_service *,
                                                    const char *,
                                                    void *),
                                         void *arg)
{
    struct binary_light *light;
    struct tansu_nwifs *nwifs;
    char udn[69];
    const unsigned char *mac;
    struct tdom_doc *doc = NULL;
    tansu_status_t ret;

    if ((light = calloc(1, sizeof(struct binary_light))) == NULL)
        return NULL;

    nwifs = tansu_nwif_getaddrs(NULL);
    if ((mac = find_valid_mac(nwifs)) == NULL)
        goto out;
    snprintf(udn, sizeof(udn),
             "uuid:00000000-0000-1010-8020-%02x%02x%02x%02x%02x%02x",
             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    if ((doc = load_doc(dd)) == NULL)
        goto out;
    if ((light->device = tansu_device_new(doc, udn)) == NULL)
        goto out;

    if ((doc = load_doc(switch_scpd)) == NULL)
        goto out;
    ret = tansu_device_add_service(light->device,
                                   "urn:schemas-upnp-org:service:SwitchPower:1",
                                   "urn:upnp-org:serviceId:SwitchPower",
                                   doc, cb, arg); 
    if (ret != TANSU_SUCCESS)
        goto out;

    light->base = tansu_upnp_base_new();
    light->base->server_name = strdup("Linux/2.6, UPnP/1.0, noname/0.1");

    tansu_upnp_base_start(evbase, light->base, 19000, nwifs);
    tansu_nwif_freeaddrs(nwifs);

    tansu_upnp_base_add_device(light->base, light->device);

    return light;

out:
    if (light)
        tansu_device_delete(light->device);
    tdom_doc_delete(doc);
    tansu_nwif_freeaddrs(nwifs);
    free(light);

    return NULL;
}

void destroy_binary_light(struct binary_light *light)
{
    tansu_upnp_base_stop(light->base);
    tansu_upnp_base_delete(light->base);
    tansu_device_delete(light->device);
    free(light);
}

